﻿/**
 * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
 * For licensing, see LICENSE.md or http://ckeditor.com/license
 */

CKEDITOR.dialog.add('colordialog', function (editor) {
    // Define some shorthands.
    var $el = CKEDITOR.dom.element,
        $doc = CKEDITOR.document,
        lang = editor.lang.colordialog;

    // Reference the dialog.
    var dialog;

    var spacer = {
        type: 'html',
        html: '&nbsp;'
    };

    var selected;

    function clearSelected() {
        $doc.getById(selHiColorId).removeStyle('background-color');
        dialog.getContentElement('picker', 'selectedColor').setValue('');
        selected && selected.removeAttribute('aria-selected');
        selected = null;
    }

    function updateSelected(evt) {
        var target = evt.data.getTarget(),
            color;

        if (target.getName() == 'td' && (color = target.getChild(0).getHtml())) {
            selected = target;
            selected.setAttribute('aria-selected', true);
            dialog.getContentElement('picker', 'selectedColor').setValue(color);
        }
    }

    // Basing black-white decision off of luma scheme using the Rec. 709 version
    function whiteOrBlack(color) {
        color = color.replace(/^#/, '');
        for (var i = 0, rgb = []; i <= 2; i++)
            rgb[i] = parseInt(color.substr(i * 2, 2), 16);
        var luma = (0.2126 * rgb[0]) + (0.7152 * rgb[1]) + (0.0722 * rgb[2]);
        return '#' + (luma >= 165 ? '000' : 'fff');
    }

    // Distinguish focused and hover states.
    var focused, hovered;

    // Apply highlight style.
    function updateHighlight(event) {
        // Convert to event.
        !event.name && (event = new CKEDITOR.event(event));

        var isFocus = !(/mouse/).test(event.name),
            target = event.data.getTarget(),
            color;

        if (target.getName() == 'td' && (color = target.getChild(0).getHtml())) {
            removeHighlight(event);

            isFocus ? focused = target : hovered = target;

            // Apply outline style to show focus.
            if (isFocus) {
                target.setStyle('border-color', whiteOrBlack(color));
                target.setStyle('border-style', 'dotted');
            }

            $doc.getById(hicolorId).setStyle('background-color', color);
            $doc.getById(hicolorTextId).setHtml(color);
        }
    }

    function clearHighlight() {
        var color = focused.getChild(0).getHtml();
        focused.setStyle('border-color', color);
        focused.setStyle('border-style', 'solid');
        $doc.getById(hicolorId).removeStyle('background-color');
        $doc.getById(hicolorTextId).setHtml('&nbsp;');
        focused = null;
    }

    // Remove previously focused style.
    function removeHighlight(event) {
        var isFocus = !(/mouse/).test(event.name),
            target = isFocus && focused;

        if (target) {
            var color = target.getChild(0).getHtml();
            target.setStyle('border-color', color);
            target.setStyle('border-style', 'solid');
        }

        if (!(focused || hovered)) {
            $doc.getById(hicolorId).removeStyle('background-color');
            $doc.getById(hicolorTextId).setHtml('&nbsp;');
        }
    }

    function onKeyStrokes(evt) {
        var domEvt = evt.data;

        var element = domEvt.getTarget();
        var relative, nodeToMove;
        var keystroke = domEvt.getKeystroke(),
            rtl = editor.lang.dir == 'rtl';

        switch (keystroke) {
            // UP-ARROW
            case 38:
                // relative is TR
                if ((relative = element.getParent().getPrevious())) {
                    nodeToMove = relative.getChild([element.getIndex()]);
                    nodeToMove.focus();
                }
                domEvt.preventDefault();
                break;
            // DOWN-ARROW
            case 40:
                // relative is TR
                if ((relative = element.getParent().getNext())) {
                    nodeToMove = relative.getChild([element.getIndex()]);
                    if (nodeToMove && nodeToMove.type == 1)
                        nodeToMove.focus();

                }
                domEvt.preventDefault();
                break;

            // SPACE
            // ENTER
            case 32:
            case 13:
                updateSelected(evt);
                domEvt.preventDefault();
                break;

            // RIGHT-ARROW
            case rtl ? 37 : 39:
                // relative is TD
                if ((nodeToMove = element.getNext())) {
                    if (nodeToMove.type == 1) {
                        nodeToMove.focus();
                        domEvt.preventDefault(true);
                    }
                }
                // relative is TR
                else if ((relative = element.getParent().getNext())) {
                    nodeToMove = relative.getChild([0]);
                    if (nodeToMove && nodeToMove.type == 1) {
                        nodeToMove.focus();
                        domEvt.preventDefault(true);
                    }
                }
                break;

            // LEFT-ARROW
            case rtl ? 39 : 37:
                // relative is TD
                if ((nodeToMove = element.getPrevious())) {
                    nodeToMove.focus();
                    domEvt.preventDefault(true);
                }
                // relative is TR
                else if ((relative = element.getParent().getPrevious())) {
                    nodeToMove = relative.getLast();
                    nodeToMove.focus();
                    domEvt.preventDefault(true);
                }
                break;
            default:
                // Do not stop not handled events.
                return;
        }
    }

    function createColorTable() {
        table = CKEDITOR.dom.element.createFromHtml('<table tabIndex="-1" aria-label="' + lang.options + '"' +
            ' role="grid" style="border-collapse:separate;" cellspacing="0">' +
            '<caption class="cke_voice_label">' + lang.options + '</caption>' +
            '<tbody role="presentation"></tbody></table>');

        table.on('mouseover', updateHighlight);
        table.on('mouseout', removeHighlight);

        // Create the base colors array.
        var aColors = ['00', '33', '66', '99', 'cc', 'ff'];

        // This function combines two ranges of three values from the color array into a row.
        function appendColorRow(rangeA, rangeB) {
            for (var i = rangeA; i < rangeA + 3; i++) {
                var row = new $el(table.$.insertRow(-1));
                row.setAttribute('role', 'row');

                for (var j = rangeB; j < rangeB + 3; j++) {
                    for (var n = 0; n < 6; n++) {
                        appendColorCell(row.$, '#' + aColors[j] + aColors[n] + aColors[i]);
                    }
                }
            }
        }

        // This function create a single color cell in the color table.
        function appendColorCell(targetRow, color) {
            var cell = new $el(targetRow.insertCell(-1));
            cell.setAttribute('class', 'ColorCell');
            cell.setAttribute('tabIndex', -1);
            cell.setAttribute('role', 'gridcell');

            cell.on('keydown', onKeyStrokes);
            cell.on('click', updateSelected);
            cell.on('focus', updateHighlight);
            cell.on('blur', removeHighlight);

            cell.setStyle('background-color', color);
            cell.setStyle('border', '1px solid ' + color);

            cell.setStyle('width', '14px');
            cell.setStyle('height', '14px');

            var colorLabel = numbering('color_table_cell');
            cell.setAttribute('aria-labelledby', colorLabel);
            cell.append(CKEDITOR.dom.element.createFromHtml('<span id="' + colorLabel + '" class="cke_voice_label">' + color + '</span>', CKEDITOR.document));
        }

        appendColorRow(0, 0);
        appendColorRow(3, 0);
        appendColorRow(0, 3);
        appendColorRow(3, 3);

        // Create the last row.
        var oRow = new $el(table.$.insertRow(-1));
        oRow.setAttribute('role', 'row');

        // Create the gray scale colors cells.
        for (var n = 0; n < 6; n++) {
            appendColorCell(oRow.$, '#' + aColors[n] + aColors[n] + aColors[n]);
        }

        // Fill the row with black cells.
        for (var i = 0; i < 12; i++) {
            appendColorCell(oRow.$, '#000000');
        }
    }

    var numbering = function (id) {
            return CKEDITOR.tools.getNextId() + '_' + id;
        },
        hicolorId = numbering('hicolor'),
        hicolorTextId = numbering('hicolortext'),
        selHiColorId = numbering('selhicolor'),
        table;

    createColorTable();

    return {
        title: lang.title,
        minWidth: 360,
        minHeight: 220,
        onLoad: function () {
            // Update reference.
            dialog = this;
        },
        onHide: function () {
            clearSelected();
            clearHighlight();
        },
        contents: [
            {
                id: 'picker',
                label: lang.title,
                accessKey: 'I',
                elements: [
                    {
                        type: 'hbox',
                        padding: 0,
                        widths: ['70%', '10%', '30%'],
                        children: [
                            {
                                type: 'html',
                                html: '<div></div>',
                                onLoad: function () {
                                    CKEDITOR.document.getById(this.domId).append(table);
                                },
                                focus: function () {
                                    // Restore the previously focused cell,
                                    // otherwise put the initial focus on the first table cell.
                                    (focused || this.getElement().getElementsByTag('td').getItem(0)).focus();
                                }
                            },
                            spacer,
                            {
                                type: 'vbox',
                                padding: 0,
                                widths: ['70%', '5%', '25%'],
                                children: [
                                    {
                                        type: 'html',
                                        html: '<span>' + lang.highlight + '</span>\
												<div id="' + hicolorId + '" style="border: 1px solid; height: 74px; width: 74px;"></div>\
												<div id="' + hicolorTextId + '">&nbsp;</div><span>' + lang.selected + '</span>\
												<div id="' + selHiColorId + '" style="border: 1px solid; height: 20px; width: 74px;"></div>'
                                    },
                                    {
                                        type: 'text',
                                        label: lang.selected,
                                        labelStyle: 'display:none',
                                        id: 'selectedColor',
                                        style: 'width: 76px;margin-top:4px',
                                        onChange: function () {
                                            // Try to update color preview with new value. If fails, then set it no none.
                                            try {
                                                $doc.getById(selHiColorId).setStyle('background-color', this.getValue());
                                            } catch (e) {
                                                clearSelected();
                                            }
                                        }
                                    },
                                    spacer,
                                    {
                                        type: 'button',
                                        id: 'clear',
                                        label: lang.clear,
                                        onClick: clearSelected
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }
        ]
    };
});
